#ifndef __SIMPLE_SINGLETON_H__
#define __SIMPLE_SINGLETON_H__

#include <unordered_map>
#include <cstdint>
#include "Utils/Hash.hpp"

namespace PocketSurvival
{
    class SimpleSingletonItem
    {
    public:
        inline virtual ~SimpleSingletonItem() {}

    protected:
        constexpr inline SimpleSingletonItem() noexcept {}
        SimpleSingletonItem(const SimpleSingletonItem &) = delete;
        SimpleSingletonItem(SimpleSingletonItem &&) = delete;
        SimpleSingletonItem &operator=(const SimpleSingletonItem &) = delete;
        SimpleSingletonItem &operator=(SimpleSingletonItem &&) = delete;
    };

    /**
     * 一个简单的单例管理类，所有经过该类管理的对象都需要继承 SimpleSingletonItem，
     * 由于内部没有使用到锁来保证注册和替换的数据安全，所以需要在初始化的时候就将所有单例对象注册上
    */
    class SimpleSingleton : public SimpleSingletonItem
    {
    private:
        std::unordered_map<size_t, SimpleSingletonItem *>  m_singletonMap;
    public:
        ~SimpleSingleton();

        /**
         * @brief 注册单例对象，每种对象(T)只能注册一次，若需要注册多次，只能以继承的方式使得对象(T)的名称改变来进行多重注册
         * 
         * @return nullptr: 该对象已经注册过了，其它: 该单例对象的指针
         * 
         * @note 返回的单例对象指针不能delete掉
        */
        template<class T>
        inline T* registerSingleton()
        {
            size_t hashCode = Utils::Hash::GetTypeHash<T>();
            if(m_singletonMap.find(hashCode) == m_singletonMap.end())
            {
                T *t = new T;
                m_singletonMap[hashCode] = t;
                return t;
            }
            return nullptr;
        }

        /**
         * @brief 获取单例对象(T)的指针
         * @return nullptr: 没有该单例对象，其它: 该单例对象的指针
        */
        template<class T>
        inline T* getSingleton()
        {
            size_t hashCode = Utils::Hash::GetTypeHash<T>();
            auto it = m_singletonMap.find(hashCode);
            if(it != m_singletonMap.end())
            {
                return static_cast<T*>(it->second);
            }
            return nullptr;
        }

        /**
         * @brief 替换或注册单例对象，若单例对象(T)存在，则会释放掉(T)，然后将(T)的位置存放(T2)的指针
         *        后面查找(T2)的单例对象时，必须用(T)的名称来查找，而不能是(T2)
         *        这个方法是专门为 Subsystem 的单例对象做的，其它单例对象最好不要用这个方法
         * 
         * @return (T2)的对象指针
         * 
         * @note 若(T)不存在，也会注册(T2)进来，但也必须用(T)的名称来查找，而不能是(T2)
        */
        template<class T, class T2>
        inline T2* replaceOrRegister()
        {
            size_t hashCode = Utils::Hash::GetTypeHash<T>();
            T2 *t2 = new T2;
            auto it = m_singletonMap.find(hashCode);
            if(it != m_singletonMap.end())
            {
                delete it->second;
                it->second = t2;
            }
            else
            {
                m_singletonMap[hashCode] = t2;
            }
            return t2;
        }

        /**
         * @brief 替换或注册单例对象，若单例对象(T)存在，这里并不会释放掉(T)
         *        然后将(T)的位置存放(T2)的指针，后面查找(T2)的单例对象时，必须用(T)的名称来查找，而不能是(T2),
         *        调用该函数前，可以通过 getSingleton() 获取(T)的指针对象，且可自行释放
         *        这个方法是专门为 Subsystem 的单例对象做的，其它单例对象最好不要用这个方法
         * 
         * @return (T2)的对象指针
         * 
         * @note 若(T)不存在，也会注册(T2)进来，但也必须用(T)的名称来查找，而不能是(T2)
        */
        template<class T, class T2>
        inline T2* replaceNotDelete()
        {
            size_t hashCode = Utils::Hash::GetTypeHash<T>();
            T2 *t2 = new T2;
            auto it = m_singletonMap.find(hashCode);
            if(it != m_singletonMap.end())
            {
                it->second = t2;
            }
            else
            {
                m_singletonMap[hashCode] = t2;
            }
            return t2;
        }

        inline const std::unordered_map<size_t, SimpleSingletonItem *> &getSingletonMap()
        {
            return m_singletonMap;
        }
    };

    inline SimpleSingleton::~SimpleSingleton()
    {
        for(auto &pair : m_singletonMap)
        {
            delete pair.second;
        }
    }

} // namespace PocketSurvival

#endif
